/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020.
 * Description: p2041_add_hwdog_node.c
 * Author: xiaojiangfeng <xiaojiangfeng@huawei.com>
 * Create: 2020-01-15
 */

#include <linux/of.h>
#include "p2041_add_hwdog_node.h"

static const char *root_path = "/";
static const char *hwdog_path = "/hwdog-feed";
static struct device_node hwdog_np;

#define OLDWTD_DTS_COMPATIBLE_STRING "arm,wtd_fixpart"
#define HWDOG_DTS_COMPATIBLE_STRING "rtos-hwdog-feed"
static struct property hwdog_comp_prop = {
	.name = "compatible",
	.length = sizeof(HWDOG_DTS_COMPATIBLE_STRING),
	.value = HWDOG_DTS_COMPATIBLE_STRING,
};
static struct property hwdog_name_prop = {
	.name = "name",
	.length = sizeof("hwdog-feed"),
	.value = "hwdog-feed",
};
#define HWDOG_NODE_ADDR_CELL_WIDTH 0x2
static unsigned long addr_cell = HWDOG_NODE_ADDR_CELL_WIDTH;
static unsigned long size_cell;
static struct property addr_cell_prop = {
	.name = "#address-cells",
	.length = sizeof(unsigned long),
	.value = &addr_cell,
};
static struct property size_cell_prop = {
	.name = "#size-cells",
	.length = sizeof(unsigned long),
	.value = &size_cell,
};

static int p2041_add_hwdog_dt_node(void)
{
	struct device_node *np = NULL;
	int err;

	np = of_find_compatible_node(NULL, NULL, HWDOG_DTS_COMPATIBLE_STRING);
	if (np) {
		pr_info("%s node is exist\n", HWDOG_DTS_COMPATIBLE_STRING);
		of_node_put(np);
		return -EINVAL;
	}

	np = of_find_compatible_node(NULL, NULL, OLDWTD_DTS_COMPATIBLE_STRING);
	if (!np) {
		pr_info("%s node is not exist\n", OLDWTD_DTS_COMPATIBLE_STRING);
		return -EINVAL;
	}
	of_node_put(np);

	hwdog_np.full_name = hwdog_path;
	(void)of_add_property(&hwdog_np, &hwdog_comp_prop);
	(void)of_add_property(&hwdog_np, &hwdog_name_prop);
	(void)of_add_property(&hwdog_np, &addr_cell_prop);
	(void)of_add_property(&hwdog_np, &size_cell_prop);
	of_node_init(&hwdog_np);

	hwdog_np.parent = of_find_node_by_path(root_path);
	if (!hwdog_np.parent) {
		pr_err("Failed to find %s\n", root_path);
		return -EINVAL;
	}

	err = of_attach_node(&hwdog_np);
	if (err)
		pr_err("Failed to add device node %s\n", hwdog_path);
	else
		pr_info("Success to add device node %s\n", hwdog_path);

	of_node_put(hwdog_np.parent);
	return err;
}

static const char *reg1_path = "/hwdog-feed/reg1";
static struct device_node reg1_np;
static struct property reg1_name_prop = {
	.name = "name",
	.length = sizeof("reg1"),
	.value = "reg1",
};

#define HWDOG_NODE_REG1_DELAY_TIME 0x2
#define HWDOG_NODE_REG_XOR_BIT 0x800000
#define HWDOG_NODE_REG_ADDR 0xffe130008
static unsigned long reg1_delay = HWDOG_NODE_REG1_DELAY_TIME;
static unsigned long reg1_xor = HWDOG_NODE_REG_XOR_BIT;
static unsigned long long reg1_reg = HWDOG_NODE_REG_ADDR;
static struct property reg1_delay_prop = {
	.name = "delay",
	.length = sizeof(unsigned long),
	.value = &reg1_delay,
};
static struct property reg1_xor_prop = {
	.name = "xor",
	.length = sizeof(unsigned long),
	.value = &reg1_xor,
};
static struct property reg1_reg_prop = {
	.name = "reg",
	.length = sizeof(unsigned long long),
	.value = &reg1_reg,
};

static void p2041_add_hwdog_reg1_node(void)
{
	struct device_node *np = NULL;
	int err;

	np = of_find_node_by_path(reg1_path);
	if (np) {
		pr_info("%s is exist\n", reg1_path);
		of_node_put(np);
		return;
	}

	reg1_np.full_name = reg1_path;
	(void)of_add_property(&reg1_np, &reg1_name_prop);
	(void)of_add_property(&reg1_np, &reg1_delay_prop);
	(void)of_add_property(&reg1_np, &reg1_xor_prop);
	(void)of_add_property(&reg1_np, &reg1_reg_prop);
	of_node_init(&reg1_np);

	reg1_np.parent = &hwdog_np;
	err = of_attach_node(&reg1_np);
	if (err)
		pr_err("Failed to add device node %s\n", reg1_path);
	else
		pr_info("Success to add device node %s\n", reg1_path);
}

void p2041_add_hwdog_node(void)
{
	int err;

	err = p2041_add_hwdog_dt_node();
	if (err)
		return;

	p2041_add_hwdog_reg1_node();
}
